package de.negativrekord.blockworld;

import cc.creativecomputing.CCApp;
import cc.creativecomputing.CCApplicationManager;
import cc.creativecomputing.control.CCControl;
import cc.creativecomputing.graphics.CCCamera;
import cc.creativecomputing.graphics.CCGraphics.CCPolygonMode;
import cc.creativecomputing.graphics.CCRenderBuffer;
import cc.creativecomputing.graphics.CCViewport;
import cc.creativecomputing.graphics.shader.CCGLSLShader;
import cc.creativecomputing.graphics.texture.CCFrameBufferObjectAttributes;
import cc.creativecomputing.graphics.texture.CCTexture2D;
import cc.creativecomputing.graphics.texture.CCTexture.CCTextureTarget;
import cc.creativecomputing.io.CCIOUtil;
import cc.creativecomputing.math.CCMath;
import cc.creativecomputing.math.CCVector3f;
import cc.creativecomputing.math.signal.CCPerlinNoise;

import com.riekoff.particlecubeworld.editor.ABrickShaderDemo;
import com.riekoff.particlecubeworld.player.AUtil;

import de.negativrekord.blockworld.MultiPathGenerator.PathStyle;
import de.negativrekord.blockworld.MultiPathGenerator.StartPositions;
import de.negativrekord.blockworld.geometry.BlockCreator;
import de.negativrekord.blockworld.geometry.BlockCreatorPresets;


public class BlockWorldDemo3 extends CCApp{

	int MAP_W = 100;
	int MAP_H = 100;
	int N_VERTICES = MAP_W*MAP_H*2*24*3;
	int W = 20;
	int scale0 = 10;
	int scale1 = 4;
	
	
	@CCControl(name="cam", min=0, max=2)
	int _cCam = 0;
	
	@CCControl(name="lvl1", min=1, max=1000)
	int alt1 = 1;
	
	@CCControl(name="noise")
	CCPerlinNoise noise = new CCPerlinNoise();
	
	
	private CCCamera cam1;
	private CCCamera cam2;
	private CCCamera cam3;
	
	private BlockCreatorPresets _myBlockCreator; 
	private KnnClassifier _myClassifier;
	private MultiPathGenerator _myPathGenerator;
	private CCRenderBuffer _myDisplayBuffer;
	
	private CCGLSLShader _myBrickShader;
	private CCGLSLShader _myDisplayShader;
	private CCTexture2D _myRandomTexture;
	
	int[][] map0 = new int[MAP_W/10][MAP_H/10];
	int[][] map1 = new int[MAP_W][MAP_H];	
	
	CCVector3f pos = new CCVector3f(0,0,0);
	CCVector3f lastPos = new CCVector3f(0,0,0);
	CCVector3f dir = new CCVector3f(0,0,0);
	
	int flash = 0;
	
	
	@Override
	public void setup() {

		cam1 = new CCCamera(g);
		cam2 = new CCCamera(g);
		cam3 = new CCCamera(g);
		
		cam1.viewport(new CCViewport (0,0,width/3,height));
		cam2.viewport(new CCViewport (width/3,0,width/3,height));
		cam3.viewport(new CCViewport (2*width/3,0,width/3,height));
		
		g.camera().far(100000);
		_myDisplayBuffer = new CCRenderBuffer(g, CCTextureTarget.TEXTURE_RECT, new CCFrameBufferObjectAttributes(), 400, 400);
		_myBrickShader = new CCGLSLShader(
				CCIOUtil.classPath (ABrickShaderDemo.class, "brick_vertex.glsl"),
				CCIOUtil.classPath (ABrickShaderDemo.class, "brick_fragment.glsl")
		);
		_myBrickShader.load();
		
		_myDisplayShader = new CCGLSLShader(
				CCIOUtil.classPath (this, "shader/display_vp.glsl"),
				CCIOUtil.classPath (this, "shader/display_fp.glsl")
		);
		_myDisplayShader.load();
		
	
	
		_myBlockCreator = new BlockCreatorPresets(N_VERTICES);
		_myBlockCreator.preset(2);
		
		_myClassifier = new KnnClassifier();
		_myClassifier.init(g);
		
		_myRandomTexture = AUtil.randomTexture(1000, 1000);
		
		_myPathGenerator = new MultiPathGenerator (20, StartPositions.RANDOM, 3000, 0, 200, 0);
		_myPathGenerator.addPath(PathStyle.PLANE, 1000, 0, 0.5f, new CCVector3f(0,-900,0));
		_myPathGenerator.addPath(PathStyle.PLANE, 1000, 1, 0.5f, new CCVector3f(0,0,0));
		_myPathGenerator.addPath(PathStyle.FREE, 100, 2, 0.5f, new CCVector3f(0,0,0));
		_myPathGenerator.addPath(PathStyle.FREE, 100, 3, 0.5f, new CCVector3f(0,0,0));
		_myPathGenerator.addPath(PathStyle.FREE, 100, 4, 0.5f, new CCVector3f(0,0,0));
		addControls("app", "app", this);
	}
	
	int rand (int min, int max) {
		return (int)CCMath.random(min,max);
	}
	float cos (float angle) {
		return CCMath.cos(angle);
	}
	
	float sin (float angle) {
		return CCMath.sin(angle);
	}
	
	float timePassed = 0;
	
	CCVector3f norm (CCVector3f theVector, float theNorm) {
		CCVector3f ret = new CCVector3f(0,0,0);
		
		int sign = CCMath.sign(theVector.x);
		ret.x = sign*CCMath.pow(CCMath.abs(theVector.x), 1/theNorm);
		
		sign = CCMath.sign(theVector.y);
		ret.y = sign*CCMath.pow(CCMath.abs(theVector.y), 1/theNorm);
		
		sign = CCMath.sign(theVector.z);
		ret.z = sign*CCMath.pow(CCMath.abs(theVector.z), 1/theNorm);
		
		return ret.normalize();
	}
	
	@Override
	public void update (float theDeltaTime) {

		_myPathGenerator.update(theDeltaTime);		
		_myClassifier.clearPrototypes();
//		for (int i=0; i<4; i++) {
//			_myClassifier.addPrototype(new CCVector3f(_myPathGenerator.pos(i).x,0,_myPathGenerator.pos(i).y), i);
//		}
		_myClassifier.addPrototype(_myPathGenerator.spline(2), 0);
		_myClassifier.addPrototype(_myPathGenerator.spline(3), 1);
		_myClassifier.addPrototype(_myPathGenerator.spline(4), 2);
		_myClassifier.init(g);
	}
	
	@Override 
	public void draw() {
		
		g.clearColor(0);
		g.clear();	
		
		CCVector3f p = _myPathGenerator.spline(0);
		CCVector3f d = _myPathGenerator.splineDir(0);
		CCVector3f t = new CCVector3f(p).add(d.scale(1000));
		cam1.position(p);
		cam1.target(t);
		cam1.up (new CCVector3f(0,1,0));
		cam1.draw(g);
		renderScene();
		
		p = _myPathGenerator.spline(1);
		d = _myPathGenerator.splineDir(1);
		t = new CCVector3f(p).add(d.scale(1000));
		cam2.position(p);
		cam2.target(t);
		cam2.up (new CCVector3f(0,1,0));
		cam2.draw(g);
		renderScene();
		
		p = _myPathGenerator.spline(2);
		d = _myPathGenerator.splineDir(2);
		t = new CCVector3f(p).add(d.scale(1000));
		cam3.position(p);
		cam3.target(t);
		cam3.up (new CCVector3f(0,1,0));
		cam3.draw(g);
		renderScene();
	}

	public void renderScene() {

		g.texture (0, _myClassifier.centers());
		g.texture (1, _myRandomTexture);
		g.polygonMode(CCPolygonMode.FILL);
//		_myBrickShader.start();
		_myDisplayShader.start();
		_myDisplayShader.uniform1i("nCenters", 5);
		_myDisplayShader.uniform1i("centers", 0);
		_myDisplayShader.uniform1i("random", 1);
		
		if (CCMath.random()<0.1f) flash = 1;
		else flash = 0;
		_myDisplayShader.uniform1i("flash", flash);
		
		
		_myBlockCreator.mesh().draw(g);
		_myDisplayShader.end();
//		_myBrickShader.end();
		g.noTexture();
		
//		g.strokeWeight(2);
//		g.color(1f);
//		g.polygonMode(CCPolygonMode.LINE);
//		_myBlockCreator.mesh().draw(g);

	}
	
	public static void main(String[] args) {
		CCApplicationManager manager = new CCApplicationManager(BlockWorldDemo3.class);
		manager.settings().size(1800, 600);
		manager.start();
	}
}
